home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-01-11 | 22.9 KB | 714 lines | [TEXT/PJMM] |
- {--------- OFFSCREEN TOYS 1.3 (boosted version) ---------}
- {by Ingemar Ragnemalm 1994-1995}
-
- {An attempt to make a simple, small, stand-alone, compatible offscreen animation demo.}
- {I made this since many people want to learn the internals of animation, which packages}
- {like SAT (Sprite Animation Toolkit) and aren't good for, even if I had included source.}
- {Source code examples should be small!}
-
- {Some good points with Offscreen Toys:}
- {- It's free, with full source code.}
- {- It's complete; no other libraries needed.}
- {- It's small, both the source and the compiled binary.}
- {- It is a real Mac application with decent event processing.}
- {- It works both with and without Color QuickDraw!}
- {- Demonstrates the use of fixed-point numbers for speed and positions.}
-
- {Some bad points:}
- {- It's not designed for re-using for complicated animation projects (which SAT is). The list}
- {of sprites is an array with no possibility to handle different kinds of sprites. (That's up to}
- {you to add if you want to build upon this.)}
- {- It doesn't give the maximum speed possible. You can make QuickDraw draw faster, and you}
- {can draw directly to screen. (SPEED CLOSE TO OPTIMAL QD FOR BOOSTED VERSION!)}
- {- It is neither MultiFinder-aware nor AppleEvent-aware.}
- {- The sprite movement isn't as trivial as it could have been, especially the collision handling}
- {but also the fixed-point positions, but hey, I need some fun too! Do we want a version that is}
- {strictly integer-based?}
- {- A few things that should be const'ed are hard-coded, i.e. the size of the icon (32x32) and}
- {the number of fixed-point "binary decimals" (4).}
-
- {Offscreen Toys 1.1 adds better collision handling, making the marbles bounce in a more}
- {realistic way.}
- {Offscreen Toys 1.2 fixes (?) the bug that sometimes caused a marble to dosappear for a}
- {few seconds.}
- {The "boosted" version uses CopyBits from an offscreen to draw the sprites rather than}
- {PlotCIcon. This should speed things up quite a bit.}
- {Version 1.3 takes out all reuseable code to a separate file. I hope that will make each part}
- {easier to understand and makes the reuseable code easily used from other programs.}
-
- program OffscreenToysPlus;
- uses
- {$IFC UNDEFINED THINK_PASCAL}
- Types, QuickDraw, Events, Windows, Dialogs, Fonts, DiskInit, TextEdit, Traps, Desk, Memory,{}
- SegLoad, Scrap, ToolUtils, OSEvents, OSUtils, Menus, Resources, Packages, {}
- {$ENDC}
- QDOffscreen, Sound, OffScreenToysUtils;
-
- { --- PART 1: Variables and constants: -----------------------------------------}
-
- const
- kAppleID = 128;
- kFileID = 129;
- kMBarHeight = 20; { We assume 20 pixels menu bar for window sizing and dragging.}
-
- kWindID = 128; { Window resource ID }
- kAboutAlertID = 128; { Alert resource ID }
-
- kSpriteNumber = 5; { Number of moving objects }
- var
- gWhoa: Boolean; {True when we want to quit}
- gCollisionFlag: Boolean; {Collisions or not?}
-
- {Menu handles}
- appleMenu, fileMenu: MenuHandle;
-
- {The window we'll be using}
- gWind: WindowPtr;
-
- {Our two offscreens:}
- offScreen, backScreen: GrafPtr;
-
- {An offscreen that the cicn is preloaded to}
- gCicn: GrafPtr;
-
- {Sprite information. In real games, I prefer making a linked list of records, like I do in}
- {SAT, and a lot more information for each, but here we want it *simple*.}
- {- position: The positions in local coordinates for the window}
- {- fixedPos: 16 times position, which gives us fixed-point numbers}
- {- speed: Speed vectors that is added to fixedPos for every frame}
- {- r: Rectangles used in drawing, for remembering what part of the screen to update}
- position, fixedPos: array[1..kSpriteNumber] of Point;
- speed: array[1..kSpriteNumber] of Point;
- r: array[1..kSpriteNumber] of Rect;
-
- {A longint that shows how big the "bowl" is (assumes circular, not oval, bowl!):}
- gBowlSize: Longint;
-
- { --- PART 2: Various general, reuseable routines, mostly glue: ---------------------}
- {All except Rand moved to OffscreenToysUtils!}
-
- function Rand (range: integer): integer;
- begin
- {Rand := abs(Random mod range) - doesn't work with CodeWarrior}
- Rand := abs(Integer(Random) mod range);
- end;
-
- { --- PART 3: Application specific routines: ---------------------------------}
-
- {mouse clicks, keydowns, background tasks and update events: This is where all}
- {the action is. :-) I include some empty procedures for you to fill in if you want to}
- {use this demo as application shell.}
-
- {Mouse click in window content}
-
- procedure DoMouse (where: Point; modifiers: Longint);
- begin
- end;
-
- {Keydown.}
-
- procedure DoKey (theKey: Char; modifiers: Longint);
- begin
- end;
-
- {DoBackground: repeating tasks - this is called repeatedly, after every event we get.}
-
- {Note: If you are making a really Mac-friendly program, this is where you should drive}
- {the animation. However, it is hard to get high framerate then, since other programs}
- {(the Finder included) will process events which will make it less smooth.}
-
- procedure DoBackground;
- const
- kWallBounce = 7; {1/10-ths of speed kept after wallbounce}
- kBallDiameterSquared = 32 * 32; {Diameter 32, squared}
- var
- tmpRect: Rect;
- i, j: integer;
- vector: Point;
- saveGD: GDHandle;
- savePort: GrafPtr;
- tmpSpeed: Point;
- squaredLength: Longint;
- p1, p2, n1, n2: Point;
-
- {Split a vector (v1) into one component parallell to another vector (direction) and one}
- {orthogonal to it. This is used to produce realistic bounces.}
- procedure SplitVector (v1, direction: Point; var parallell, normal: Point);
- var
- l2, v1pr: Longint;
- begin
- {parallell := direction * (v1 DOT direction) /|direction|**2}
- {normal := v1 - parallell}
-
- l2 := direction.h * direction.h + direction.v * direction.v; {Squared length of "direction"}
- v1pr := v1.h * direction.h + v1.v * direction.v; {Scalar product}
-
- parallell.h := direction.h * v1pr div l2;
- parallell.v := direction.v * v1pr div l2;
- normal.h := v1.h - parallell.h;
- normal.v := v1.v - parallell.v;
- end;
-
- {A rather boring subroutine that moves the sprites i and j away from each other.}
- {I almost didn't want to put this in, making the demo unnecessarily big, but I wanted}
- {decent collisions. If anyone can suggest a better (simpler) collision handling for circular}
- {objects, I'd be happy to put it in.}
- {I use a line drawing algorithm for it. I'm sure there are better ways. This is of questionable}
- {value as reuseable code - depends on your application.}
- procedure Separate (i, j: integer);
- var
- initVector, nowVector: Point;
- absH, absV: integer;
- moveH, moveV: integer;
- frac: integer;
- {Normal signum function (which I don't think is in the libs)}
- function Sgn (x: integer): integer;
- begin
- if x > 0 then
- Sgn := 1
- else if x < 0 then
- Sgn := -1
- else
- Sgn := 0;
- end;
-
- begin {Separate}
- frac := 0;
- initVector.h := position[i].h - position[j].h;
- initVector.v := position[i].v - position[j].v;
- absH := abs(initVector.h);
- absV := abs(initVector.v);
- moveH := Sgn(initVector.h);
- moveV := Sgn(initVector.v);
- if moveH = 0 then
- if moveV = 0 then
- moveV := 1;
- repeat
- if absH > absV then
- begin
- position[i].h := position[i].h + moveH;
- position[j].h := position[j].h - moveH;
- frac := frac + absV;
- if frac > absH then
- begin
- position[i].v := position[i].v + moveV;
- position[j].v := position[j].v - moveV;
- frac := frac - absH;
- end
- end
- else
- begin
- position[i].v := position[i].v + moveV;
- position[j].v := position[j].v - moveV;
- frac := frac + absH;
- if frac > absV then
- begin
- position[i].h := position[i].h + moveH;
- position[j].h := position[j].h - moveH;
- frac := frac - absV;
- end
- end;
-
- nowVector.h := position[i].h - position[j].h;
- nowVector.v := position[i].v - position[j].v;
- until longint(nowVector.h) * nowVector.h + longint(nowVector.v) * nowVector.v > kBallDiameterSquared;
- fixedPos[i].h := BSL(position[i].h, 4); {Make fixedPos by shifting in the 4 binary "decimals"}
- fixedPos[i].v := BSL(position[i].v, 4);
- fixedPos[j].h := BSL(position[j].h, 4); {Make fixedPos by shifting in the 4 binary "decimals"}
- fixedPos[j].v := BSL(position[j].v, 4);
- end;
-
- begin {DoBackground}
- OTGetGWorld(savePort, saveGD); {Save the port/device}
- {1: Erase all sprites from offScreen}
- {Note: We keep the rectangles r[i] for erasing on the screen, later.}
- OTSetGWorld(offScreen, nil);
- for i := 1 to kSpriteNumber do
- begin
- r[i] := gCicn^.portRect;
- OffsetRect(r[i], position[i].h, position[i].v);
- CopyBits(backScreen^.portBits, offScreen^.portBits, r[i], r[i], srcCopy, nil);
- end;
- {2: Change the position and speed}
- for i := 1 to kSpriteNumber do
- begin
- {Modify fixed-point position by speed}
- fixedPos[i].h := fixedPos[i].h + speed[i].h;
- fixedPos[i].v := fixedPos[i].v + speed[i].v;
-
- {Make position by shifting away the 4 binary "decimals"}
- if fixedPos[i].h >= 0 then
- position[i].h := BSR(fixedPos[i].h, 4)
- else
- position[i].h := BitOr(BSR(fixedPos[i].h, 4), $f000);
- if fixedPos[i].v >= 0 then
- position[i].v := BSR(fixedPos[i].v, 4)
- else
- position[i].v := BitOr(BSR(fixedPos[i].v, 4), $f000);
-
- if fixedPos[i].h + speed[i].h < 0 then
- speed[i].h := abs(speed[i].h) * kWallBounce div 10 + 1;
- if fixedPos[i].v + speed[i].v < 0 then
- speed[i].v := abs(speed[i].v) * kWallBounce div 10 + 1;
- if position[i].h + gCicn^.portRect.right > offScreen^.portRect.right then
- speed[i].h := -abs(speed[i].h) * kWallBounce div 10 - 1;
- if position[i].v + gCicn^.portRect.bottom > offScreen^.portRect.bottom then
- speed[i].v := -abs(speed[i].v) * kWallBounce div 10 - 1;
-
- {Are we in the bowl? If we are, accelerate towards the center.}
- vector.h := position[i].h + 16 - BSR(offScreen^.portRect.right, 1);
- vector.v := position[i].v + 16 - BSR(offScreen^.portRect.bottom, 1);
- if (vector.h * vector.h + vector.v * vector.v) < gBowlSize then
- begin
- speed[i].h := speed[i].h - vector.h div 2;
- speed[i].v := speed[i].v - vector.v div 2;
- end;
- end; {position/speed loop}
-
- {Check for collisions}
- if gCollisionFlag then
- for i := 1 to kSpriteNumber - 1 do {For all objects except the last}
- for j := i + 1 to kSpriteNumber do {compare its position to all following objects}
- begin
- {Find the vector between them}
- vector.h := position[i].h - position[j].h;
- vector.v := position[i].v - position[j].v;
- squaredLength := longint(vector.h) * vector.h + longint(vector.v) * vector.v;
- {If it is shorter than the diameter of a ball…}
- if squaredLength < kBallDiameterSquared then
- begin
- {Move them away from each other}
- Separate(i, j);
- {Swap the speed components that are parallell to "vector" (this allows for "touches", very}
- {nice and realistic bounces)}
- SplitVector(speed[i], vector, p1, n1);
- SplitVector(speed[j], vector, p2, n2);
-
- speed[j].h := p1.h + n2.h;
- speed[j].v := p1.v + n2.v;
-
- speed[i].h := p2.h + n1.h;
- speed[i].v := p2.v + n1.v;
-
- {Old Offscren Toys just swapped the speed, as commented out below. This is not as realistic.}
- {tmpSpeed := speed[i];}
- {speed[i] := speed[j];}
- {speed[j] := tmpSpeed;}
-
- {Play a sound. This is not a sound demo, so I removed the sound.}
- end;
- end; {collision loop}
-
- {3: Draw sprites in offScreen}
- {Note: PlotCIcon (OTPlotCicn) is not very fast! We can speed it up my pre-drawing them in some}
- {offscreen, and CopyBits them from there. THAT IS DONE IN THIS VERSION!!!}
- for i := 1 to kSpriteNumber do
- begin
- tmpRect := gCicn^.portRect;
- OffsetRect(tmpRect, position[i].h, position[i].v);
- OTPlotBoostCicn(gCicn, offScreen, tmpRect.topLeft);
- {FrameOval(tmpRect); {SÅ LÄNGE…}
- end;
-
- {4: Copy sprites to the screen (gWind) - both old and new position!}
- {Note: Depending on what limitations we have on movement, we may be able to avoid the multiple}
- {CopyBitsing here. E.g. if sprites always move a maximum of 2 pixels, we can copy a 2 pixels}
- {larger area, etc.}
- OTSetGWorld(gWind, saveGD); {Vilken GD???}
- for i := 1 to kSpriteNumber do
- begin
- CopyBits(offScreen^.portBits, gWind^.portBits, r[i], r[i], srcCopy, nil);
- r[i] := gCicn^.portRect;
- OffsetRect(r[i], position[i].h, position[i].v);
- CopyBits(offScreen^.portBits, gWind^.portBits, r[i], r[i], srcCopy, nil);
- end;
- OTSetGWorld(savePort, saveGD);
- end; {DoBackground}
-
- {DoUpdate: handle update events, in this case by copying offScreen to the screen (gWind).}
-
- {Note to beginners: A program without update events processing is not a real Mac program!}
- {All drawing you do must reach the update event handler in some way, or it might be lost,}
- {or worse, partially erased, which is really ugly.}
-
- procedure DoUpdate;
- var
- saveGD: GDHandle;
- savePort: GrafPtr;
- begin
- OTGetGWorld(savePort, saveGD);
- SetPort(gWind); {or OTSetGWorld(gWind, GetMainDevice), in case I forget to et back the device?}
- BeginUpdate(gWind);
- {Do drawing here - in this case a CopyBits}
- CopyBits(offScreen^.portBits, gwind^.portBits, gwind^.portRect, gwind^.portRect, srcCopy, nil);
- EndUpdate(gWind);
- OTSetGWorld(savePort, saveGD);
- end;
-
- {DoAppleMenu and DoFileMenu: handle menu selections}
-
- procedure DoAppleMenu (item: integer);
- var
- str: Str255;
- h: Handle;
- saveGD: GDHandle;
- savePort: GrafPtr;
- ignore: integer;
- begin
- if item = 1 then
- begin
- if Alert(kAboutAlertID, nil) = 1 then
- ; {Ignore result}
- end
- else
- {Apple menu other than "About": Code from TransSkel}
- begin
- OTGetGWorld(savePort, saveGD); {I guess GetPort would be ok}
- GetItem(appleMenu, item, str);
- SetResLoad(false);
- h := GetNamedResource('DRVR', str);
- SetResLoad(true);
- if h <> nil then
- begin
- ResrvMem(SizeResource(h) + $1000);
- ignore := OpenDeskAcc(str);
- end;
- OTSetGWorld(savePort, saveGD);
- end;
- end; {DoAppleMenu}
-
- procedure DoFileMenu (item: integer);
- var
- start, finish, frames: Longint;
- begin
- case item of
- 1:
- {Run animation without event processing until the user clicks the mouse}
- {Note: This runs the animation at maximum speed. In real programs, we}
- {must limit the speed with the system clock, e.g. inspect TickCount.}
- begin
- start := TickCount;
- frames := 0;
- while not Button do
- begin
- DoBackground;
- frames := frames + 1;
- end;
- finish := TickCount;
- ParamText(stringof(frames * 60 div (finish - start), ' frames/second'), '', '', '');
- if Alert(129, nil) = 1 then
- ;
- end;
-
- {To run the animation only, without measuring frames/sec, you just have to d this:}
- {while not Button do}
- {DoBackground;}
- 2:
- begin
- gCollisionFlag := not gCollisionFlag;
- CheckItem(fileMenu, 2, gCollisionFlag);
- end;
- {Set the flag that tells the program to quit.}
- 4:
- gWhoa := true;
- end; {case}
- end; {DoFileMenu}
-
- { --- PART 4: Event processing: -----------------------------------------}
-
- {MenuSelection: Menu selection by mouse or command-key:}
-
- procedure MenuSelection (whatSelection: longInt);
- begin
- case HiWord(whatSelection) of
- kAppleID:
- DoAppleMenu(LoWord(whatSelection));
- kFileID:
- DoFileMenu(LoWord(whatSelection));
- end; {case}
- HiLiteMenu(0);
- end;
-
- {MainLoop: get and process events. This is the boring standard part of all programs. I prefer}
- {using TransSkel to get rid of it. I don't here since I want this code to be stand-alone.}
-
- procedure MainLoop;
- const
- kSleep = 5; {Real programs may modify the sleep time depending on whether or not they are in the front}
- var
- hasEvent: Boolean;
- theEvent: EventRecord;
- theKey: Char;
- whatSelection: Longint;
- whichPart: integer;
- whichWindow: WindowPtr;
- r: rect;
- begin
- {Get the next event. Use WaitNextEvent if possible.}
- if gHasWNE then
- hasEvent := WaitNextEvent(everyEvent, theEvent, kSleep, nil)
- else
- begin
- SystemTask;
- hasEvent := GetNextEvent(everyEvent, theEvent);
- end;
-
- {OK, so what happened then?}
- if hasEvent then
- case theEvent.what of
- mouseDown:
- begin
- whichPart := FindWindow(theEvent.where, whichWindow);
- case whichPart of
- inMenuBar:
- begin
- whatSelection := MenuSelect(theEvent.where);
- MenuSelection(whatSelection);
- end;
- inSysWindow:
- SystemClick(theEvent, whichWindow);
- inGoAway:
- if (TrackGoAway(whichWindow, theEvent.where)) then
- gWhoa := true;
- inDrag:
- begin
- if (whichWindow <> FrontWindow) and (BitAnd(theEvent.modifiers, cmdKey) = 0) then
- SelectWindow(whichWindow);
- {$IFC UNDEFINED THINK_PASCAL}
- r := qd.screenBits.bounds; {How big is the screen? (Note: Don't use screenBits for other things: it isn't a valid BitMap any more!)}
- {$ELSEC}
- r := screenBits.bounds; {How big is the screen? (Note: Don't use screenBits for other things: it isn't a valid BitMap any more!)}
- {$ENDC}
- r.top := r.top + kMBarHeight; { Skip down past menu bar }
- InsetRect(r, 4, 4);
- DragWindow(whichWindow, theEvent.where, r);
- end;
- inGrow:
- ; {Ignored - we don't resize}
- inContent:
- if (whichWindow <> FrontWindow) then
- SelectWindow(whichWindow)
- else
- DoMouse(theEvent.where, theEvent.modifiers); {Go to application-specific mouse down handling}
- end; {case whichPart}
- end; {mouseDown}
- keyDown, autoKey:
- begin
- theKey := char(BitAnd(theEvent.message, charCodeMask));
- if (BitAnd(theEvent.modifiers, cmdKey) <> 0) then
- MenuSelection(MenuKey(theKey))
- else
- DoKey(theKey, theEvent.modifiers);
- end;
- updateEvt:
- {There's only one window to bother with here, but let's make sure that's the one the Mac wants to update.}
- if WindowPtr(theEvent.message) = gWind then
- DoUpdate;
- {Handle disk inserts like TransSkel.}
- diskEvt:
- if (HiWord(theEvent.message) <> noErr) then
- begin
- DILoad;
- if DIBadMount(Point($00400040), theEvent.message) = 0 then
- ;
- DIUnload;
- end; {diskEvt}
- otherwise {Other events are ignored}
- end; {case}
-
- DoBackground;
- end;
-
- { --- PART 5: Initializations: -----------------------------------------}
-
- {OTInit: Initialize global flags, menus and window}
-
- procedure OTInit;
- const
- {Trap numbers}
- _WaitNextEvent = $A860;
- _GetCIcon = $AA1E; {E.g. any Color QuickDraw routine}
- k32bQD = $AB1D;
- _SndPlay = $A805;
- begin
-
- {In case this isn't Think Pascal we have to make the standard inits ourselves.}
- {$IFC UNDEFINED THINK_PASCAL}
- InitGraf(@qd.thePort);
- InitFonts;
- InitWindows;
- InitMenus;
- TEInit;
- InitDialogs(nil);
- {InitCursor;}
- MaxApplZone;
- {$ENDC}
-
- OTInitGlobals; {Initialize the OffscreenToysUtils unit}
-
- gWhoa := false;
- gCollisionFlag := false;
-
- {We could check with Gestalt instead, but that isn't necessary here since we aren't using any}
- {optional services (like QuickTime).}
-
- {Get the window, a color window if we are going to use color.}
- if gColorQDFlag then
- gWind := GetNewCWindow(kWindId, nil, WindowPtr(-1))
- else
- gWind := GetNewWindow(kWindId, nil, WindowPtr(-1));
-
- {Some menus. We could read these from resources.}
- appleMenu := NewMenu(kAppleID, stringof(char($14)));
- AppendMenu(appleMenu, 'About OffscreenToys…;(-');
- AddResMenu(appleMenu, 'DRVR');
- InsertMenu(appleMenu, 0); { put apple menu at end of menu bar }
- fileMenu := NewMenu(kFileID, 'File');
- AppendMenu(fileMenu, 'Try max speed;Collisions;(-;Quit/Q');
- InsertMenu(fileMenu, 0); { put file menu at end of menu bar }
- DrawMenuBar;
- end;
-
- {OTOffscreensInit: Initialize offscreen grafports (worlds) and draw in them.}
-
- procedure OTOffscreensInit;
- var
- saveGD: GDHandle;
- savePort: GrafPtr;
- thePat: PixPatHandle;
- r: Rect;
- i: integer;
- colorFlag: Boolean;
- const
- patID = 128;
-
- {A little routine for setting the forecolor with a single line.}
- procedure OTForeColor (red, green, blue: integer);
- var
- theColor: RGBColor;
- begin
- theColor.red := red;
- theColor.green := green;
- theColor.blue := blue;
- RGBForeColor(theColor);
- end;
-
- begin {OTOffscreensInit}
- OTGetGWorld(savePort, saveGD);
-
- OTNewGWorld(offScreen, gWind^.portRect);
- OTNewGWorld(backScreen, gWind^.portRect);
-
- OTSetGWorld(backScreen, nil);
-
- {Do some drawing in backScreen. First, we paint a pattern (using a 'ppat' resource):}
-
- {For drawing the background, let's make a local flag that tells us if we shold draw}
- {b/w patterns or color ones.}
- if gColorQDFlag then
- colorFlag := (CGrafPtr(backScreen)^.portPixMap^^.pixelSize > 1)
- else
- colorFlag := false;
-
- if colorFlag then
- begin
- thePat := GetPixPat(patID);
- PenPixPat(thePat)
- end
- else
- begin
- thePat := PixPatHandle(GetResource('ppat', patID));
- PenPat(thePat^^.pat1Data);
- end;
- PaintRect(backScreen^.portRect);
- PenNormal;
-
- {Then we draw some circles.}
-
- r := backScreen^.portRect;
- InsetRect(r, (r.right - r.left) div 8, (r.bottom - r.top) div 8);
- gBowlSize := longint(r.right - r.left) * (r.right - r.left) div 4; {Tells how big the "bowl" is!}
- if colorFlag then
- begin
- OTForeColor(-10000, -10000, -10000);
- PaintOval(r);
- end
- else
- {$IFC UNDEFINED THINK_PASCAL}
- FillOval(r, qd.ltGray);
- {$ELSEC}
- FillOval(r, ltGray);
- {$ENDC}
-
- InsetRect(r, (r.right - r.left) div 8, (r.bottom - r.top) div 8);
- if colorFlag then
- begin
- OTForeColor(-25000, -25000, -25000);
- PaintOval(r);
- end
- else
- {$IFC UNDEFINED THINK_PASCAL}
- FillOval(r, qd.gray);
- {$ELSEC}
- FillOval(r, gray);
- {$ENDC}
-
- InsetRect(r, (r.right - r.left) div 6, (r.bottom - r.top) div 6);
- if colorFlag then
- begin
- OTForeColor(20000, 20000, 20000);
- PaintOval(r);
- end
- else
- {$IFC UNDEFINED THINK_PASCAL}
- FillOval(r, qd.dkGray);
- {$ELSEC}
- FillOval(r, dkGray);
- {$ENDC}
-
- InsetRect(r, (r.right - r.left) div 5, (r.bottom - r.top) div 5);
- if colorFlag then
- OTForeColor(0, 0, 0);
- PaintOval(r);
-
- {Done drawing!}
- {For your own hacks, consider using a PICT resource and use GetPicture and DrawPicture to draw the}
- {background. Note that you'll need both a color and a b/w picture if you want it to look good in b/w.}
-
- OTSetGWorld(offScreen, nil);
- CopyBits(backScreen^.portBits, offScreen^.portBits, backScreen^.portRect, backScreen^.portRect, srcCopy, nil);
-
- OTSetGWorld(savePort, saveGD);
-
- {Get the cicn resource}
- {Note: You can, of course, use several cicns and switch between.}
- gCicn := OTGetBoostCicn(128);
-
- {Initialize the sprite information arrays:}
-
- for i := 1 to kSpriteNumber do
- begin
- position[i].h := Rand(offScreen^.portRect.right - 32);
- position[i].v := (i - 1) * (offScreen^.portRect.bottom - 32) div 5 + Rand((offScreen^.portRect.bottom - 32) div 5);
- fixedPos[i].h := BSL(position[i].h, 4);
- fixedPos[i].v := BSL(position[i].v, 4);
- speed[i].h := Random mod 32;
- speed[i].v := Random mod 32;
- end;
- end;
-
- { --- MAIN PROGRAM BODY: -----------------------------------------}
-
- begin
- OTInit; {General initializations}
- OTOffscreensInit; {Set up the offscreen grafports}
- InitCursor; {Set the cursor to arrow in case it isn't.}
-
- {Run until quit or click in the close box.}
- repeat
- MainLoop;
- until gWhoa;
-
- {No cleanup is necessary here.}
- {We could DisposeGWorld, but that isn't necessary when we are quitting.}
- end.